package com.chartHandle.excelService.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.enums.WriteDirectionEnum;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.alibaba.excel.write.metadata.fill.FillWrapper;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.chartHandle.bean.*;
import com.chartHandle.config.ConfigRead;
import com.chartHandle.config.SmokeAnticipatedOrder;
import com.chartHandle.excelService.handle.WeeklySupplyStrategyDataHandler;
import com.chartHandle.excelService.handle.WeeklySupplyStrategyDataMerge;
import com.chartHandle.excelService.service.WriteWeeklySupplyStrategyDataService;
import com.chartHandle.util.ExcelUtil;
import com.chartHandle.bean.CellStyleWY;
import com.projectCommon.bean.constant.Constant;
import com.projectCommon.bean.Smoke;
import com.projectCommon.bean.easyExcel.*;
import com.projectCommon.bean.easyExcel.putTactics.*;
import com.projectCommon.util.commonUtil.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class WriteWeeklySupplyStrategyDataServiceImpl implements WriteWeeklySupplyStrategyDataService {
    @Autowired
    private SmokeAnticipatedOrder smokeAnticipatedOrder;
    @Autowired
    private ConfigRead configRead;

    /**
     * @param excelTypeEnum            excel文件类型
     * @param weeklySupplyStrategyData 基本数据
     * @return 返回对应的文件图片
     */
    @Override
    public byte[] writeTemplate1(ExcelTypeEnum excelTypeEnum, WeeklySupplyStrategyData weeklySupplyStrategyData, Map<String, Smoke> dbInfo) {
        // 获取基本填充数据
        GearSelection gearSelection = weeklySupplyStrategyData.getGearSelection();
        List<PriceSelection> priceSelection = weeklySupplyStrategyData.getPriceSelection();
        List<GearExtendSelection> gearExtendSelectionList = weeklySupplyStrategyData.getGearExtendSelectionList();
        Map<String, String> noteInformationMap = weeklySupplyStrategyData.getNoteInformationMap();
        List<GearAddLabelSelection> gearAddLabelSelectionList = weeklySupplyStrategyData.getGearAddLabelSelectionList();

        // 模板文件 输入流
        ByteArrayInputStream inputStream = new ByteArrayInputStream(smokeAnticipatedOrder.getTemplateFileByte());

        // 定义准备写入excel的数据
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        List<AnticipatedRelease> gearPutList = new ArrayList<>();
        List<AnticipatedRelease> pricePutList = new ArrayList<>();
        List<AnticipatedRelease> gearExtendPutList = new ArrayList<>();
        List<AnticipatedRelease> gearAddLabelList = new ArrayList<>();

        // 获取档位投放数据
        for (AnticipatedOrderData anticipatedOrderData : gearSelection.getList()) {
            AnticipatedRelease anticipatedRelease = anticipatedOrderDataToAnticipatedRelease(dbInfo, anticipatedOrderData);
            gearPutList.add(anticipatedRelease);
        }

        // 将档位投放数据进行排序
        sort(gearPutList);

        // 获取价格投放数据
        for (PriceSelection selection : priceSelection) {
            List<AnticipatedOrderData> list = selection.getList();
            for (AnticipatedOrderData anticipatedOrderData : list) {
                AnticipatedRelease anticipatedRelease = anticipatedOrderDataToAnticipatedRelease(dbInfo, anticipatedOrderData);
                pricePutList.add(anticipatedRelease);
            }
            //  通过这个对象代替，对应的限制数量
            AnticipatedRelease anticipatedRelease = listToAnticipatedRelease(selection.getGearPutUpperLimit());
            anticipatedRelease.setName("价位段订购上限");
            pricePutList.add(anticipatedRelease);
        }

        // 为了可以改变单元格合并的方式 在前面多加一行
        gearExtendPutList.add(new AnticipatedRelease(null));
        //  获取档位扩展投放方式 的 数据
        for (GearExtendSelection gearExtendSelection : gearExtendSelectionList) {
            List<AnticipatedOrderData> list = gearExtendSelection.getList();
            for (int i = 0; i < list.size(); i++) {
                AnticipatedRelease anticipatedRelease = anticipatedOrderDataToAnticipatedRelease(dbInfo, list.get(i));
                if (i != 0) {
                    anticipatedRelease.setName(null);
                    anticipatedRelease.setWholePrice(null);
                    anticipatedRelease.setAlloType(null);
                }
                gearExtendPutList.add(anticipatedRelease);
            }
        }
        // 获取挡位+标签投投放的填充数据
        gearAddLabelList.add(new AnticipatedRelease(null));
        for (GearAddLabelSelection gearAddLabelSelection : gearAddLabelSelectionList) {
            List<AnticipatedOrderData> list = gearAddLabelSelection.getList();
            for (int i = 0; i < list.size(); i++) {
                AnticipatedRelease anticipatedRelease = anticipatedOrderDataToAnticipatedRelease(dbInfo, list.get(i));
                if (i != 0) {
                    anticipatedRelease.setName(null);
                    anticipatedRelease.setWholePrice(null);
                    anticipatedRelease.setAlloType(null);
                }
                gearAddLabelList.add(anticipatedRelease);
            }
        }

        // 得到单纯实际订购的有效数据，根据当前的商户业态的出来的,为了计算业态
        List<AnticipatedRelease> allValidData = getAllValidData(
                gearExtendSelectionList,
                priceSelection,
                gearAddLabelSelectionList,
                dbInfo,
                gearPutList);

        // 根据上面的所有信息得到下面的统计信息
        List<PutStatistics> putStatisticsList = getPutStatistics(allValidData);

        // 得到需要显示的挡位信息
        int[] orderDetailGearS = smokeAnticipatedOrder.getOrderDetailGearS();
        // 得到订单每个档位的详细数据
        List<OrderDetail> orderDetails = getOrderDetailList(allValidData, putStatisticsList, orderDetailGearS);
        Map<String, Integer> baseHeightMap = getBaseHeight(
                gearPutList,
                pricePutList,
                gearExtendPutList,
                gearAddLabelList,
                orderDetails);
        Integer gearPutBaseHeight = baseHeightMap.get("gearPutBaseHeight");
        Integer pricePutBaseHeight = baseHeightMap.get("pricePutBaseHeight");
        Integer gearExtendPutBaseHeight = baseHeightMap.get("gearExtendPutBaseHeight");
        Integer gearAddLabelBaseHeight = baseHeightMap.get("gearAddLabelBaseHeight");
        Integer orderDetailBaseHeight = baseHeightMap.get("orderDetailBaseHeight");
        Integer remarkBaseHeight = baseHeightMap.get("remarkBaseHeight");

        List<TemplateRemark> remarkList = smokeAnticipatedOrder.getAnticipatedOrderRemarks();
        remarkList = convertRemarks(remarkList);
        // 这个字段是 挡位标签投放 每一组数据的数量
        List<Integer> gearAndLabelCombination = new ArrayList<>();
        for (int i = 0; i < gearAddLabelSelectionList.size(); i++) {
            GearAddLabelSelection gearAddLabelSelection = gearAddLabelSelectionList.get(i);
            int size = gearAddLabelSelection.getList().size();
            gearAndLabelCombination.add(size);
        }
        // 得到订单详情的每一行的行高
        List<RowObj> heightList = getOrderDetailListHeight(orderDetails, orderDetailBaseHeight, remarkList, remarkBaseHeight);
        // 超过行高自动换行
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        headWriteCellStyle.setWrapped(true);
        ExcelWriter excelWriterBuild = EasyExcel
                .write(byteArrayOutputStream)
                .withTemplate(inputStream)
                .excelType(excelTypeEnum)
                .registerWriteHandler(new WeeklySupplyStrategyDataHandler(
                        getStyleMap(gearPutList,
                                gearPutBaseHeight,
                                pricePutList,
                                pricePutBaseHeight
                        ), 3))
                .registerWriteHandler(new WeeklySupplyStrategyDataMerge(getMergeData(
                        gearPutList,
                        pricePutList,
                        gearExtendPutList,
                        gearAddLabelList,
                        gearAndLabelCombination,
                        smokeAnticipatedOrder,
                        orderDetails,
                        remarkList,
                        gearPutBaseHeight,
                        pricePutBaseHeight,
                        gearExtendPutBaseHeight,
                        gearAddLabelBaseHeight,
                        orderDetailBaseHeight,
                        remarkBaseHeight)))
                .registerWriteHandler(new HorizontalCellStyleStrategy(headWriteCellStyle, headWriteCellStyle))
                .build();
        FillConfig fillConfig_VERTICAL = FillConfig.builder().direction(WriteDirectionEnum.VERTICAL).forceNewRow(Boolean.TRUE).build();
        FillConfig fillConfig_HORIZONTAL = FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build();
        WriteSheet build = EasyExcel.writerSheet().build();
        excelWriterBuild.fill(new FillWrapper("gear", gearPutList), fillConfig_VERTICAL, build);
        excelWriterBuild.fill(new FillWrapper("price", pricePutList), fillConfig_VERTICAL, build);
        excelWriterBuild.fill(new FillWrapper("gearExtend", gearExtendPutList), fillConfig_VERTICAL, build);
        excelWriterBuild.fill(new FillWrapper("gearAddLabel", gearAddLabelList), fillConfig_VERTICAL, build);
        excelWriterBuild.fill(new FillWrapper("statistics", putStatisticsList), fillConfig_HORIZONTAL, build);
        excelWriterBuild.fill(new FillWrapper("orderDetail", orderDetails), fillConfig_VERTICAL, build);
        excelWriterBuild.fill(new FillWrapper("remarks", remarkList), fillConfig_VERTICAL, build);

        excelWriterBuild.fill(getMap(noteInformationMap, gearSelection.getGearPutUpperLimit()), build);
        excelWriterBuild.finish();
        // 美化excel 二次读取excel。做一些easyExcel 不太方便做的事情
        List<Integer> deleteLine = new ArrayList<>();
        if (!(gearExtendSelectionList.size() == 0)) {
            deleteLine.add(gearExtendPutBaseHeight + 1);
        }
        if (!(orderDetails.size() == 0)) {
            deleteLine.add(orderDetailBaseHeight + 1);
        }
        deleteLine.add(remarkBaseHeight + 1);
        // 二次处理excel 表格
        ByteArrayOutputStream beautificationRes = beautification(deleteLine, heightList, byteArrayOutputStream.toByteArray());
        return beautificationRes.toByteArray();
    }

    // 需要添加空行并且对字符串做一些处理
    private static List<TemplateRemark> convertRemarks(List<TemplateRemark> remarkList) {
        // 1. 拷贝一下吧。为了解耦，反正内存直接释放了，影响不大。
        List<TemplateRemark> newRemarkList = new ArrayList<>();
        newRemarkList.add(new TemplateRemark());
        for (int i = 0; i < remarkList.size(); i++) {
            TemplateRemark anticipatedOrderRemark = remarkList.get(i);
            List<String> contentList = anticipatedOrderRemark.getContentList();
            StringBuilder strContent = new StringBuilder();
            for (int j = 0; j < contentList.size(); j++) {
                strContent.append(contentList.get(j)).append("\n");
            }
            anticipatedOrderRemark.setContent(strContent.toString());
            newRemarkList.add(remarkList.get(i));
        }
        return newRemarkList;
    }

    /**
     * 美化处理单元格，主要解决easyExcel 不太好解决的问题
     *
     * @param deleteIndexList 删除的行 从0 开始数
     * @param rowObjs         设置指定行为指定的高度
     * @param bytes           数据
     * @return 返回处理后的数据
     */
    private static ByteArrayOutputStream beautification(List<Integer> deleteIndexList, List<RowObj> rowObjs, byte[] bytes) {
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        Workbook workbook = null;
        try {
            workbook = new HSSFWorkbook(byteArrayInputStream);
            Sheet sheet = workbook.getSheetAt(0); // 获取第一个工作表
            // 设置指定行的行高
            for (Integer integer : deleteIndexList) {
                Row row = sheet.getRow(integer - 1);
                if (row != null) {
                    row.setHeightInPoints(0);
                }
            }
            if (rowObjs != null) {
                for (RowObj rowObj : rowObjs) {
                    Row row = sheet.getRow(rowObj.getRowIndex() - 1);
                    if (row != null) {
                        row.setHeightInPoints(rowObj.getRowHeight());
                    }
                }
            }
            // 保存修改后的Excel文件
            try {
                workbook.write(byteArrayOutputStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
            workbook.close();
            byteArrayOutputStream.close();
        } catch (IOException e) {
            log.error("delete fail ,{}", e.getMessage());
        }
        return byteArrayOutputStream;
    }


    /**
     * 得到这个行号是为了后续方便 计算样式的位置
     */
    private Map<String, Integer> getBaseHeight(List<AnticipatedRelease> gearList,
                                               List<AnticipatedRelease> pricePutList,
                                               List<AnticipatedRelease> gearExtendPutList,
                                               List<AnticipatedRelease> gearAddLabelList,
                                               List<OrderDetail> orderDetails) {
        HashMap<String, Integer> baseHeightMap = new HashMap<>();
        int[] listIntervalS = smokeAnticipatedOrder.getListIntervalS();
        int gearSize = gearList.size();
        int pricePutSize = pricePutList.size();
        // 如果没有数据的话 size是1 和其他的空行处理不同， 其他空行是添加了一个 null 对象，但是这里没有  TODO：有问题
        pricePutSize = pricePutSize != 0 ? pricePutSize : 1;
        int gearExtendPutSize = gearExtendPutList.size();
        int gearAddLabelSize = gearAddLabelList.size();
        int orderDetailSize = orderDetails.size();
        int gearPutBaseHeight = listIntervalS[0];
        int pricePutBaseHeight = gearSize + gearPutBaseHeight + listIntervalS[1];
        int gearExtendPutBaseHeight = pricePutSize + pricePutBaseHeight + listIntervalS[2];
        int gearAddLabelBaseHeight = gearExtendPutSize + gearExtendPutBaseHeight + listIntervalS[3];
        int orderDetailBaseHeight = gearAddLabelSize + gearAddLabelBaseHeight + listIntervalS[4];
        int remarkBaseHeight = orderDetailSize + orderDetailBaseHeight + listIntervalS[5];

        baseHeightMap.put("gearPutBaseHeight", gearPutBaseHeight);
        baseHeightMap.put("pricePutBaseHeight", pricePutBaseHeight);
        baseHeightMap.put("gearExtendPutBaseHeight", gearExtendPutBaseHeight);
        baseHeightMap.put("gearAddLabelBaseHeight", gearAddLabelBaseHeight);
        baseHeightMap.put("orderDetailBaseHeight", orderDetailBaseHeight);
        baseHeightMap.put("remarkBaseHeight", remarkBaseHeight);
        return baseHeightMap;
    }

    /**
     * 得到订购详情的行高
     * 得到需要改变行高的对象集合信息
     *
     * @param orderDetails 订购详情
     * @return 订单详情行信息
     */
    private List<RowObj> getOrderDetailListHeight(List<OrderDetail> orderDetails,
                                                  Integer orderDetailBaseHeight,
                                                  List<TemplateRemark> remarkList,
                                                  Integer remarkBaseHeight) {
        List<RowObj> rowObjs = new ArrayList<>();
        for (int i = 0; i < orderDetails.size(); i++) {
            OrderDetail orderDetail = orderDetails.get(i);
            if (orderDetail.getGear() != null && orderDetail.getDetailStr() != null) {
                String detailStr = orderDetail.getDetailStr();
                int height = ((detailStr.length() / 133) + 1) * smokeAnticipatedOrder.getBaseRowHeightS();
                RowObj rowObj = new RowObj();
                rowObj.setRowIndex(orderDetailBaseHeight + i + 1);
                rowObj.setRowHeight((short) height);
                rowObjs.add(rowObj);
            }
        }
        for (int i = 0; i < remarkList.size(); i++) {
            TemplateRemark anticipatedOrderRemark = remarkList.get(i);
            if (anticipatedOrderRemark.getContent() != null) {
                int size = anticipatedOrderRemark.getContentList().size();
                int height = (size) * smokeAnticipatedOrder.getBaseRowHeightS();
                RowObj rowObj = new RowObj();
                rowObj.setRowIndex(remarkBaseHeight + i + 1);
                rowObj.setRowHeight((short) height);
                rowObjs.add(rowObj);
            }
        }
        return rowObjs;
    }

    /**
     * 根据所有可订购的数据将某些档位的具体订购通过字符串的形式输出
     *
     * @param allValidData      所有有效的数据
     * @param putStatisticsList 档位统计信息
     * @param gears             显示档位
     * @return 返回档位细节对象
     */
    private List<OrderDetail> getOrderDetailList(List<AnticipatedRelease> allValidData, List<PutStatistics> putStatisticsList, int[] gears) {
        List<OrderDetail> orderDetails = new ArrayList<>();
        orderDetails.add(new OrderDetail());
        for (int j = 0; j < gears.length; j++) {
            int gearLv = gears[j];
            OrderDetail orderDetail = new OrderDetail();
            orderDetail.setGear(Constant.AREA_TYPE_VILLAGE + " " + gearLv + " 档");
            StringBuilder orderStrDetail = new StringBuilder();
            sort(allValidData);
            for (int i = 0; i < allValidData.size(); i++) {
                AnticipatedRelease anticipatedRelease = allValidData.get(i);
                String gearValue = anticipatedRelease.getGearValue(gearLv);
                if (!gearValue.equals("0")) {
                    String smokeName = anticipatedRelease.getName();
                    orderStrDetail.append(StringUtils.replaceParenthesis(smokeName)).append("*[").append(gearValue).append("]").append(",");
                }
            }
            PutStatistics putStatistics = putStatisticsList.get(configRead.getHighestGear() - gearLv);
            orderDetail.setAllotypeNum(putStatistics.getAllotypePutNum() + "");
            orderDetail.setGeneralNum(putStatistics.getGeneralPutNum() + "");
            orderDetail.setOrderAmount(putStatistics.getAmount());
            orderDetail.setTotal(putStatistics.getTotalPutNum() + "");
            orderStrDetail.append("常规:").append(orderDetail.getGeneralNum()).append(",").
                    append("异型:").append(orderDetail.getAllotypeNum()).append(",").
                    append("共计:").append(orderDetail.getTotal()).append(",").
                    append("订单金额:").append(orderDetail.getOrderAmount()).append(".");
            orderDetail.setDetailStr(orderStrDetail.toString());
            orderDetails.add(orderDetail);
        }
        return orderDetails;
    }

    /**
     * 获取样式map
     *
     * @param gearList 档位数据集合
     * @return 返回一个样式map
     */
    private Map<PointXY, CellStyleWY> getStyleMap(List<AnticipatedRelease> gearList,
                                                  int gearPutBaseHeight,
                                                  List<AnticipatedRelease> pricePutList,
                                                  int pricePutBaseHeight) {
        HashMap<PointXY, CellStyleWY> pointXYCellStyleWYHashMap = new HashMap<>();
        int[] enhanceColorGearLvS = smokeAnticipatedOrder.getEnhanceColorGearLvS();
        short enhanceColor = Short.parseShort(smokeAnticipatedOrder.getEnhanceColor());
        int totalColumn = configRead.getHighestGear() + Integer.parseInt(smokeAnticipatedOrder.getPreGearLvColumnNum());
        // 价格自选颜色填充
        int priceUpLimitColumnNum = 0;
        short priceSelectUpLimitColor = Short.parseShort(smokeAnticipatedOrder.getPriceSelectUpLimitColor());
        // 挡位投档的颜色填充
        for (int i = 0; i < gearList.size(); i++) {
            for (int x = 0; x < totalColumn; x++) {
                PointXY pointXY = new PointXY(x, i + gearPutBaseHeight);
                CellStyleWY cellStyleWY = new CellStyleWY();
                cellStyleWY.setCellType('0');
                ExcelUtil.fillCellColor(cellStyleWY, i, smokeAnticipatedOrder.getLineColorS());
                int currentGearLv = totalColumn - x;
                for (int enhanceColorGearLv : enhanceColorGearLvS) {
                    if (enhanceColorGearLv == currentGearLv) {
                        cellStyleWY.setColorIndex(enhanceColor);
                        break;
                    }
                }
                pointXYCellStyleWYHashMap.put(pointXY, cellStyleWY);
            }
        }
        for (int i = 0; i < pricePutList.size(); i++) {
            AnticipatedRelease anticipatedRelease = pricePutList.get(i);
            boolean isPriceUpLimit = "价位段订购上限".equals(anticipatedRelease.getName());
            short colorIndex = isPriceUpLimit ? priceSelectUpLimitColor : ExcelUtil.getFillCellColor(i - priceUpLimitColumnNum, smokeAnticipatedOrder.getLineColorS2());
            for (int x = 0; x < totalColumn; x++) {
                int currentGearLv = totalColumn - x;
                CellStyleWY cellStyleWY = new CellStyleWY();
                cellStyleWY.setCellType('0');
                PointXY pointXY = new PointXY(x, i + pricePutBaseHeight);
                boolean containFlag = StringUtils.containsNumber(enhanceColorGearLvS, currentGearLv);
                if (!isPriceUpLimit && containFlag) {
                    cellStyleWY.setColorIndex(enhanceColor);
                } else {
                    cellStyleWY.setColorIndex(colorIndex);
                }
                pointXYCellStyleWYHashMap.put(pointXY, cellStyleWY);
            }
            if (isPriceUpLimit) {
                priceUpLimitColumnNum++;
            }
        }
        return pointXYCellStyleWYHashMap;
    }

    /**
     * 获取需要合并单元格的数据
     *
     * @param gearList              档位投放的list
     * @param pricePutList          价格投放的list
     * @param gearExtendPutList     档位扩展投放的list
     * @param smokeAnticipatedOrder 基本的bean信息
     * @return 返回需要合并的单元格的数据
     */
    private static Map<PointXY, MergeBean> getMergeData(List<AnticipatedRelease> gearList,
                                                        List<AnticipatedRelease> pricePutList,
                                                        List<AnticipatedRelease> gearExtendPutList,
                                                        List<AnticipatedRelease> gearAddLabelList,
                                                        List<Integer> gearAddLabelMergeColumn,
                                                        SmokeAnticipatedOrder smokeAnticipatedOrder,
                                                        List<OrderDetail> gearOrderDetails,
                                                        List<TemplateRemark> remarkList,
                                                        Integer gearPutBaseHeight,
                                                        Integer pricePutBaseHeight,
                                                        Integer gearExtendPutBaseHeight,
                                                        Integer gearAddLabelBaseHeight,
                                                        Integer orderDetailBaseHeight,
                                                        Integer remarkBaseHeight) {

        Map<PointXY, MergeBean> pointXYMergeBeanHashMap = new HashMap<>();
        CellStyleWY commonBorderStyle = new CellStyleWY();
        commonBorderStyle.setDownBorderStyle(BorderStyle.THIN);
        // 档位投放的合并区间
        for (int i = 0; i < gearList.size(); i++) {
            PointXY pointXYStart = new PointXY(1, gearPutBaseHeight + i);
            PointXY pointXYEnd = new PointXY(2, gearPutBaseHeight + i);
            MergeBean mergeBean = new MergeBean();
            mergeBean.setStart(pointXYStart);
            mergeBean.setEnd(pointXYEnd);
            mergeBean.setStyleWY(commonBorderStyle);
            pointXYMergeBeanHashMap.put(pointXYStart, mergeBean);
        }
        CellStyleWY priceRangeOrderingLimit = new CellStyleWY();
        priceRangeOrderingLimit.setDownBorderStyle(BorderStyle.THIN);
        // 价格自选投放的合并区间
        for (int i = 0; i < pricePutList.size(); i++) {
            AnticipatedRelease anticipatedRelease = pricePutList.get(i);
            PointXY pointXYStart;
            PointXY pointXYEnd;
            if (anticipatedRelease.getName().equals("价位段订购上限")) {
                pointXYStart = new PointXY(0, pricePutBaseHeight + i);
                pointXYEnd = new PointXY(Integer.parseInt(smokeAnticipatedOrder.getPreGearLvColumnNum()) - 1, pricePutBaseHeight + i);
                priceRangeOrderingLimit.setHorizontalAlignment(HorizontalAlignment.RIGHT);
            } else {
                pointXYStart = new PointXY(1, pricePutBaseHeight + i);
                pointXYEnd = new PointXY(2, pricePutBaseHeight + i);
            }
            MergeBean mergeBean = new MergeBean();
            mergeBean.setStart(pointXYStart);
            mergeBean.setEnd(pointXYEnd);
            mergeBean.setStyleWY(commonBorderStyle);
            pointXYMergeBeanHashMap.put(pointXYStart, mergeBean);
        }
        // 档位扩展投放的合并区间
        CellStyleWY gearExtendPutMergeStyle = new CellStyleWY();
        gearExtendPutMergeStyle.setLeftBorderStyle(BorderStyle.THIN);
        gearExtendPutMergeStyle.setRightBorderStyle(BorderStyle.THIN);
        for (int i = 1; i < gearExtendPutList.size(); ) {
            int[] mergeColumn = {0, 1, 3};
            for (int index : mergeColumn) {
                PointXY pointXYStartName = new PointXY(index, gearExtendPutBaseHeight + i);
                PointXY pointXYEndName = new PointXY(index, gearExtendPutBaseHeight + i + 1);
                MergeBean mergeBeanName = new MergeBean();
                mergeBeanName.setStart(pointXYStartName);
                mergeBeanName.setEnd(pointXYEndName);
                mergeBeanName.setStyleWY(gearExtendPutMergeStyle);
                pointXYMergeBeanHashMap.put(pointXYStartName, mergeBeanName);
            }
            i = i + 2;
        }
        CellStyleWY orderDetailCellStyleWY = new CellStyleWY();
        orderDetailCellStyleWY.setDownBorderStyle(BorderStyle.THIN);
        orderDetailCellStyleWY.setRightBorderStyle(BorderStyle.THICK);

        // 挡位+标签的合并区间

        int size = gearAddLabelMergeColumn.size();
        for (int i = 0; i < size; i++) {
            int[] mergeColumn = {0, 1, 3};
            for (int index : mergeColumn) {
                Integer pre = null;
                if ((i - 1) < 0) {
                    pre = 0;
                } else {
                    pre = gearAddLabelMergeColumn.get(i - 1);
                }
                Integer next = gearAddLabelMergeColumn.get(i);

                PointXY pointXYStartName = new PointXY(index, gearAddLabelBaseHeight + pre);
                PointXY pointXYEndName = new PointXY(index, gearAddLabelBaseHeight + i + next - 1);
                MergeBean mergeBeanName = new MergeBean();
                mergeBeanName.setStart(pointXYStartName);
                mergeBeanName.setEnd(pointXYEndName);
                pointXYMergeBeanHashMap.put(pointXYStartName, mergeBeanName);
            }
        }

//        for (int i = 0; i < gearAddLabelList.size(); i++) {
//            int[] mergeColumn = {0, 1, 3};
//            for (int index : mergeColumn) {
//                PointXY pointXYStartName = new PointXY(index, gearAddLabelBaseHeight + i);
//                PointXY pointXYEndName = new PointXY(index, gearAddLabelBaseHeight + i + 1);
//                MergeBean mergeBeanName = new MergeBean();
//                mergeBeanName.setStart(pointXYStartName);
//                mergeBeanName.setEnd(pointXYEndName);
//                pointXYMergeBeanHashMap.put(pointXYStartName, mergeBeanName);
//            }
//        }
        // 订单详情的合并位置
        for (int i = 0; i < gearOrderDetails.size(); i++) {
            PointXY pointXYStart = new PointXY(1, orderDetailBaseHeight + i);
            PointXY pointXYEnd = new PointXY(33, orderDetailBaseHeight + i);

            MergeBean mergeBeanName = new MergeBean();
            mergeBeanName.setStart(pointXYStart);
            mergeBeanName.setEnd(pointXYEnd);
            mergeBeanName.setStyleWY(orderDetailCellStyleWY);
            pointXYMergeBeanHashMap.put(pointXYStart, mergeBeanName);
        }
        // 注意事项的合并区间
        for (int i = 0; i < remarkList.size(); i++) {
            PointXY pointXYStart = new PointXY(1, remarkBaseHeight + i + 1);
            PointXY pointXYEnd = new PointXY(33, remarkBaseHeight + i + 1);
            MergeBean mergeBeanName = new MergeBean();
            mergeBeanName.setStart(pointXYStart);
            mergeBeanName.setEnd(pointXYEnd);
            mergeBeanName.setStyleWY(orderDetailCellStyleWY);
            pointXYMergeBeanHashMap.put(pointXYStart, mergeBeanName);
        }
        return pointXYMergeBeanHashMap;
    }

    /**
     * 根据所有有效的数据
     *
     * @param allValidData 所有订购的有效数据
     * @return 返回统计数据
     */
    private List<PutStatistics> getPutStatistics(List<AnticipatedRelease> allValidData) {
        List<PutStatistics> putStatisticsList = new ArrayList<>();
        for (int i = 0; i < BaseGearInfo.levelNum; i++) {
            PutStatistics putStatistics = new PutStatistics();
            int generalPutNum = 0;
            int allotypePutNum = 0;
            BigDecimal amount = new BigDecimal("0");

            for (AnticipatedRelease data : allValidData) {
                int quantity = Integer.parseInt(data.getGearValue(configRead.getHighestGear() - i));
                boolean isAllotype = Constant.CHAR_TRUE.equals(data.getAlloType());
                boolean isCity = Constant.AREA_TYPE_CITY.equals(data.getCityOrVillage());
                if (data.getCityOrVillage() == null || isCity) {
                    if (isAllotype) {
                        allotypePutNum += quantity;
                    } else {
                        generalPutNum += quantity;
                    }
                }
                if (quantity != 0) {
                    String wholeSalePrice = parseWholePrice(data.getWholePrice());
                    amount = amount.add(new BigDecimal(quantity).multiply(new BigDecimal(wholeSalePrice)));
                }
            }

            int totalPutNum = generalPutNum + allotypePutNum;
            putStatistics.setGeneralPutNum(generalPutNum);
            putStatistics.setAllotypePutNum(allotypePutNum);
            putStatistics.setTotalPutNum(totalPutNum);
            putStatistics.setAmount(amount.setScale(0, RoundingMode.UP).toString());
            putStatisticsList.add(putStatistics);
        }
        return putStatisticsList;
    }

    /**
     * 得到所有的有效数据，指的是已经区分了农网和城网，单独把有效的数据罗列出来
     *
     * @param gearExtendSelectionList 挡位扩展数据
     * @param priceSelectionList      价格选择数据
     * @param dbInfo                  数据库数据
     * @param gearPutList             档位投放数据
     * @return 返回有效数据
     */
    private List<AnticipatedRelease> getAllValidData(List<GearExtendSelection> gearExtendSelectionList,
                                                     List<PriceSelection> priceSelectionList,
                                                     List<GearAddLabelSelection> gearAddLabelSelectionList,
                                                     Map<String, Smoke> dbInfo,
                                                     List<AnticipatedRelease> gearPutList) {
        // 档位投放处理
        List<AnticipatedRelease> validAnticipatedReleases = new ArrayList<>(gearPutList);
        // 档位扩展投放
        for (GearExtendSelection gearExtendSelection : gearExtendSelectionList) {
            for (AnticipatedOrderData anticipatedOrderData : gearExtendSelection.getList()) {
                AnticipatedRelease select = anticipatedOrderDataToAnticipatedRelease(dbInfo, anticipatedOrderData);
                if (select.getCityOrVillage().equals("农网")) {
                    validAnticipatedReleases.add(select);
                }
            }
        }
        // 挡位+标签投放的选择
        for (GearAddLabelSelection gearAddLabelSelection : gearAddLabelSelectionList) {
            AnticipatedRelease selectedRelease = null;

            for (AnticipatedOrderData anticipatedOrderData : gearAddLabelSelection.getList()) {
                AnticipatedRelease release = anticipatedOrderDataToAnticipatedRelease(dbInfo, anticipatedOrderData);
                if ("传统便利店".equals(release.getCityOrVillage())) {
                    selectedRelease = release;
                    break;
                }
            }

            if (selectedRelease == null) {
                for (AnticipatedOrderData anticipatedOrderData : gearAddLabelSelection.getList()) {
                    AnticipatedRelease release = anticipatedOrderDataToAnticipatedRelease(dbInfo, anticipatedOrderData);
                    if ("其他".equals(release.getCityOrVillage())) {
                        selectedRelease = release;
                        break;
                    }
                }
            }

            if (selectedRelease != null) {
                validAnticipatedReleases.add(selectedRelease);
            } else {
                throw new RuntimeException("没有找到符合条件的挡位+标签投放数据, 如果抛出异常就说明是代码或者逻辑的问题了，因为没有其他这一项，不应该出现这种情况。");
            }
        }

        // 价格自选投放，最后的结果是一个每个档位，每种卷烟，在当前价格区间 `选择` 哪几个
        for (PriceSelection priceSelection : priceSelectionList) {
            List<AnticipatedOrderData> list = priceSelection.getList();
            // 将数据格式转换一下
            List<AnticipatedRelease> convertResult = list.stream()
                    .map(anticipatedOrderData -> anticipatedOrderDataToAnticipatedRelease(dbInfo, anticipatedOrderData))
                    .collect(Collectors.toCollection(ArrayList::new));

            sort(convertResult);
            for (int gear_index = 0; gear_index < configRead.getHighestGear(); gear_index++) {
                int gear = configRead.getHighestGear() - gear_index;
                // 当前档位当前选择集订购上限
                Integer currentGearSelectUpperLimit = priceSelection.getGearPutUpperLimit().get(gear_index);
                if (currentGearSelectUpperLimit <= 0) {
                    continue;
                }
                // 实际订购，也可以算是当前订购的一种计算。记录的一个中间变量计算结果
                int actualOrder = 0;
                for (int i = 0; i < convertResult.size(); i++) {
                    AnticipatedRelease anticipatedRelease = convertResult.get(i);
                    // 当前价格段选择，当前档位，当前卷烟订购上限
                    int currentGearSelectCurrentSmokeUpperLimit = Integer.parseInt(anticipatedRelease.getGearValue(gear));
                    // 有三种情况，如果当前档位订购 加 当前档位当前卷烟的订购 大于/等于/小于 当前挡位选择上限
                    // TODO: 下面有一个 判断   int i1 = i + 1; if (i1 <= i) {   不记得是干啥了。
                    // 这个字段是实际订购的期待订购，这个字段是预计的，不是实际的，就是一个临时变量。
                    int actualOrderEstimate = actualOrder + currentGearSelectCurrentSmokeUpperLimit;
                    if (actualOrder <= currentGearSelectUpperLimit && actualOrderEstimate > currentGearSelectUpperLimit) {
                        anticipatedRelease.setGearValue(gear, currentGearSelectUpperLimit - actualOrder + "");
                        break;
                    } else if (actualOrderEstimate == currentGearSelectUpperLimit) {
                        int i1 = i + 1;
                        if (i1 <= i) {
                            for (int j = i1; j < convertResult.size(); j++) {
                                convertResult.get(j).setGearValue(gear, "0");
                            }
                        }
                        break;
                    } else if (actualOrderEstimate < currentGearSelectUpperLimit) {
                        actualOrder += currentGearSelectCurrentSmokeUpperLimit;
                    }
                }
            }
            validAnticipatedReleases.addAll(convertResult);
        }

        return validAnticipatedReleases;
    }

    private static AnticipatedRelease anticipatedOrderDataToAnticipatedRelease(Map<String, Smoke> dbInfo, AnticipatedOrderData anticipatedOrderData) {
        AnticipatedRelease anticipatedRelease = new AnticipatedRelease();
        anticipatedRelease.setName(anticipatedOrderData.getProductName());
        anticipatedRelease.setProductCode(anticipatedOrderData.getProductEncoding());
        if (dbInfo.get(anticipatedOrderData.getProductEncoding()) == null) {
            anticipatedRelease.setWholePrice(getNewPrice(anticipatedOrderData.getPriceBand()));
            log.warn("{} 批发价缺失", anticipatedRelease.getName());
        } else {
            anticipatedRelease.setWholePrice(dbInfo.get(anticipatedOrderData.getProductEncoding()).getWholeSalePrice());
        }
        anticipatedRelease.setCityOrVillage(anticipatedOrderData.getType());
        anticipatedRelease.setAlloType(anticipatedOrderData.getAbnormal());
        anticipatedRelease.setPriceBand(anticipatedOrderData.getPriceBand());
        anticipatedRelease.copyLevel(anticipatedOrderData);
        return anticipatedRelease;
    }

    // 将集合转换城 一个对象。对应  AnticipatedRelease 对象
    private static AnticipatedRelease listToAnticipatedRelease(List<Integer> list) {
        AnticipatedRelease anticipatedRelease = new AnticipatedRelease();
        String[] lvs = new String[list.size()];
        for (int i = 0; i < list.size(); i++) {
            lvs[i] = String.valueOf(list.get(i));
        }
        anticipatedRelease.setData(lvs);
        return anticipatedRelease;
    }

    // 将档位投放合计写入 map
    private Map<String, String> getMap(Map<String, String> noteInformationMap, List<Integer> gearPutUpperLimit) {
        Map<String, String> maps = new HashMap<>();
        maps.put("dateRange", noteInformationMap.get("dateRange"));
        for (int i = 0; i < gearPutUpperLimit.size(); i++) {
            maps.put("gearTotalPut_" + (configRead.getHighestGear() - i), gearPutUpperLimit.get(i).toString());
        }
        return maps;
    }

    /**
     * 按照价格对 卷烟进行排序，由于有些卷烟的价格是未知的，我们需要对价格进行一个转换
     *
     * @param anticipatedReleaseList 卷烟列表
     */
    private static void sort(List<AnticipatedRelease> anticipatedReleaseList) {
        anticipatedReleaseList.sort((o1, o2) -> {
            int i1 = (int) Double.parseDouble(parseWholePrice(o1.getWholePrice()));
            int i2 = (int) Double.parseDouble(parseWholePrice(o2.getWholePrice()));
            return i1 - i2;
        });
    }

    /**
     * 得到新的价格
     *
     * @param priceStr 价格字符串
     * @return 处理原本的价格字符串得到一个新的价格字符串
     */
    private static String getNewPrice(String priceStr) {
        // 处理 "800元(含)以上" 类型的字符串、
        if (priceStr == null) {
            System.out.println(11);
        }
        if (priceStr.contains("以上")) {
            String processedString = priceStr.replace("元", "").replace("(", "").replace(")", "").replace("含", "");
            String[] parts = processedString.split("以上");
            if (parts.length > 0) {
                try {
                    int threshold = Integer.parseInt(parts[0].trim());
                    return "[>" + threshold + "]";
                } catch (NumberFormatException e) {
                    return priceStr;
                }
            }
        }
        // 处理 "[600-800元)" 类型的字符串
        else if (priceStr.startsWith("[") || priceStr.endsWith(")")) {
            String processedString = priceStr.replace("元", "");
            String[] parts = processedString.substring(1, processedString.length() - 1).split("-");
            if (parts.length == 2) {
                try {
                    int lowerBound = Integer.parseInt(parts[0].trim());
                    int upperBound = Integer.parseInt(parts[1].trim());
                    return "[" + lowerBound + "-" + upperBound + ")";
                } catch (NumberFormatException e) {
                    return priceStr;
                }
            }
        }
        return priceStr;
    }

    /**
     * 解析字符串，将 [600-800) 这种字符串，解析成600  800元(含)以上 这种字符串解析成800
     *
     * @param priceStr 显示的价格字符串
     * @return 解析这个字符串，得到一个新的价格，用于计算或者排序
     */
    private static String parseWholePrice(String priceStr) {
        if (priceStr.contains(">") || priceStr.contains("<")) {
            String replace = priceStr.replace(">", "").replace("<", "").replace("[", "").replace("]", "");
            return Integer.parseInt(replace) + "";
        } else if (priceStr.startsWith("[") && priceStr.endsWith(")")) {
            // 处理 "[600-800)" 类型的字符串
            String[] parts = priceStr.substring(1, priceStr.indexOf(")")).split("-");
            if (parts.length == 2) {
                return Integer.parseInt(parts[0].trim()) + "";
            }
        } else if (priceStr.matches("-?\\d+(\\.\\d+)?")) {
            return Double.parseDouble(priceStr) + "";
        }
        throw new IllegalArgumentException("Invalid price range string format: " + priceStr);
    }
}
